package chelydra.sharelydra.client.webservice;

import chelydra.sharelydra.client.Core;
import chelydra.sharelydra.client.friend.Friend;
import chelydra.sharelydra.client.friend.Notification;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Map;
import java.util.Vector;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 *
 * @author Pierre-Élie Fauché
 */
public class XMLParser {

	private WebserviceManager manager;

	public XMLParser(WebserviceManager manager) {
		this.manager = manager;
	}

	public String processResponse(InputStream input)
	throws WebserviceException {
		String result = "An error occurred";
		try {
			BufferedInputStream inputBuffer = new BufferedInputStream(input);
			DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			Document document = db.parse(inputBuffer);
			Element rootElement = (Element)document.getDocumentElement();

			String responseType = rootElement.getAttribute("type");
			if (responseType.contentEquals("success")) {
				this.processSuccess(rootElement);
				result = null;
			} else if (responseType.contentEquals("fail")) {
				result = this.processFail(rootElement);
			}
			
			input.close();
			
		} catch (Exception ex) {
			ex.printStackTrace(System.err);
			throw new WebserviceException(ex.getMessage());
		}

		return result;
	}

	private void processSuccess(Element root) {
		this.processAction(root);
		this.processProfile(root);
		this.processFriends(root);
		this.processNotifications(root);
	}

	private String processFail(Element root) {
		Element messageElement = (Element)root.getElementsByTagName("message").item(0);
		if (messageElement!=null) {
			return messageElement.getTextContent();
		}
		return "An unknown error occured";
	}

	private void processAction(Element root) {
		Element actionElement = (Element)root.getElementsByTagName("action").item(0);
		if (actionElement!=null) {
			Element actionNameElement = (Element)actionElement.getElementsByTagName("name").item(0);
			if (actionNameElement!=null) {
				String actionName = actionNameElement.getTextContent();
				if (actionName.contentEquals("search")) {
					this.processActionSearch(actionElement);
				}
				// TODO add other actions
			}
		}
	}

	private void processProfile(Element root) {
		Element profileElement = (Element)root.getElementsByTagName("profile").item(0);
		if (profileElement!=null) {
			NodeList attributes = profileElement.getChildNodes();
			Map<String,String> map = new Hashtable();

			for (int i=0; i<attributes.getLength(); i++) {
				if (attributes.item(i).getNodeType()==Node.ELEMENT_NODE) {
					Element attribute = (Element)attributes.item(i);
					map.put(attribute.getTagName(), attribute.getTextContent());
				}
			}

			Core.getApplication().getDatabaseManager().updateUserInformation(map.get("lastName"),
							map.get("firstName"), map.get("email"), map.get("nickname"), 
							map.get("hideInSearch"), map.get("hideEmail"));
			Core.getApplication().getView().updateProfile();
		}
	}

	private void processFriends(Element root) {
		NodeList friendsLists = root.getElementsByTagName("friends");
		Map<String,Friend> newFriends = new Hashtable();

		if (friendsLists.getLength()>0) {
			Element friendsList = (Element)friendsLists.item(0);
			NodeList friends = friendsList.getElementsByTagName("friend");
			for (int i=0; i<friends.getLength(); i++) {
				try {
					Friend f = this.processFriend((Element)friends.item(i));
					newFriends.put(f.getLogin(), f);
				} catch (Exception ex) {
					ex.printStackTrace(System.err);
				} // catch
			} // for
		}// if

		Core.getApplication().getFriendManager().updateFriends(newFriends);
	}

	private void processNotifications(Element root) {
		String login = Core.getApplication().getDatabaseManager().getUserInformation().get("UserLogin");

		NodeList notificationsLists = root.getElementsByTagName("notifications");
		if (notificationsLists.getLength()>0) {
			Collection<Notification> newNotes = new Vector();
			Element notificationsList = (Element)notificationsLists.item(0);
			NodeList notifications = notificationsList.getElementsByTagName("notification");
			for (int i=0; i<notifications.getLength(); i++) {
				try {
					Notification n = this.processNotification((Element) notifications.item(i));
					n.setReceiverLogin(login);
					newNotes.add(n);
				} catch (Exception ex) {
					ex.printStackTrace(System.err);
				}
			} // for

			Core.getApplication().getDatabaseManager().addNewNotifications(newNotes);
			Core.getApplication().getView().updateNotifications();

		} // if
	}

	private Friend processFriend(Element friend) throws Exception {
		Friend newFriend = null;

		NodeList attributes = friend.getChildNodes();
		Map<String,String> attributesMap = Friend.getEmptyAttributesMap();

		for (int i=0; i<attributes.getLength(); i++) {
			if (attributes.item(i).getNodeType()==Node.ELEMENT_NODE) {
				Element attribute = (Element)attributes.item(i);
				attributesMap.put(attribute.getTagName(), attribute.getTextContent());
			}
		}
		newFriend = new Friend(attributesMap);

		return newFriend;
	}

	private Notification processNotification(Element notification) throws Exception {
		Notification note = null;

		NodeList attributes = notification.getChildNodes();
		Map<String,String> attributesMap = Notification.getEmptyAttributesMap();

		for (int i=0; i<attributes.getLength(); i++) {
			if (attributes.item(i).getNodeType()==Node.ELEMENT_NODE) {
				Element attribute = (Element)attributes.item(i);
				if (attribute.getTagName().contentEquals("sender")) {
					NodeList senderAttributes = attribute.getChildNodes();
					for (int j=0; j<senderAttributes.getLength(); j++) {
						if (senderAttributes.item(j).getNodeType()==Node.ELEMENT_NODE) {
							Element senderAttribute = (Element)senderAttributes.item(j);
							if (senderAttribute.getTagName().contentEquals("login")) {
								attributesMap.put("senderLogin", senderAttribute.getTextContent());
							} else if (senderAttribute.getTagName().contentEquals("nickname")) {
								attributesMap.put("senderNickname", senderAttribute.getTextContent());
							}
						}
					}
				} else {
					attributesMap.put(attribute.getTagName(), attribute.getTextContent());
				}
			}
		}
		note = new Notification(attributesMap);

		return note;
	}

	private void processActionSearch(Element actionElement) {
		Element usersList = (Element)actionElement.getElementsByTagName("users").item(0);
		if (usersList!=null) {
			Collection< Map<String,String> > usersFound = new Vector();
			NodeList users = usersList.getElementsByTagName("user");
			for (int i=0; i<users.getLength(); i++) {
				Element user = (Element)users.item(i);
				NodeList attributes = user.getChildNodes();
				Map<String,String> userAttributes = new Hashtable();
				for (int j=0; j<attributes.getLength(); j++) {
					if (attributes.item(j).getNodeType()==Node.ELEMENT_NODE) {
						Element attribute = (Element)attributes.item(j);
						userAttributes.put(attribute.getTagName(), attribute.getTextContent());
					}
				}
				usersFound.add(userAttributes);
			} // for

			Core.getApplication().getFriendManager().updateSearchFriends(usersFound);

		} // if
	}

}
